#include "tcp_server.h"
#include "log.h"

// Done

const static uint64_t g_tcp_server_read_timeout = 60 * 100082;

TcpServer::TcpServer(IOManager *io_worker, IOManager *accept_worker)
    : m_ioWorker(io_worker), m_acceptWorker(accept_worker), m_recvTimeout(g_tcp_server_read_timeout), m_name("tcpServer/1.0.0"), m_type("tcp"), m_isStop(true)
{
}

TcpServer::~TcpServer()
{
    for (auto &sock : m_socks)
    {
        sock->close();
    }
    m_socks.clear();
}

bool TcpServer::bind(Address::ptr addr)
{
    std::vector<Address::ptr> addrs;
    std::vector<Address::ptr> fails;
    addrs.push_back(addr);
    return bind(addrs, fails);
}

bool TcpServer::bind(const std::vector<Address::ptr> &addrs, std::vector<Address::ptr> &fails)
{
    for (auto &addr : addrs)
    {
        Socket::ptr sock = Socket::CreateTCP(addr);
        if (!sock->bind(addr))
        {
            LOG(ERROR, "bind faild erron = %d,errstr = %s,addr=[ %s, ]", errno, strerror(errno), addr->toString());
            fails.push_back(addr);
            continue;
        }
        if (!sock->listen())
        {
            LOG(ERROR, "listen faild erron = %d,errstr = %s,addr=[ %s, ]", errno, strerror(errno), addr->toString());
            fails.push_back(addr);
            continue;
        }
        m_socks.push_back(sock);
    }
    if (!fails.empty())
    {
        m_socks.clear();
        return false;
    }
    for (auto &sock : m_socks)
    {
        LOG(DEBUG, "type = %d name = %s,server bind success: %p", m_type, m_name.c_str(), sock.get());
    }
    return true;
}

void TcpServer::startAccept(Socket::ptr sock)
{
    while (!m_isStop)
    {
        Socket::ptr client = sock->accept();
        if (client)
        {
            client->setRecvTimeout(m_recvTimeout);
            m_ioWorker->schedule(std::bind(&TcpServer::handleClient, shared_from_this(), client));
        }
        else
        {
            LOG(ERROR, "accept error,errno = %d errstr = %s", errno, strerror(errno));
        }
    }
}

bool TcpServer::start()
{
    if (!isStop())
    {
        return true;
    }
    m_isStop = false;
    for (auto &sock : m_socks)
    {
        m_acceptWorker->schedule(std::bind(&TcpServer::startAccept, shared_from_this(), sock));
    }
}

void TcpServer::stop()
{
    m_isStop = true;
    auto self = shared_from_this();
    m_acceptWorker->schedule([this, self]()
                             {
        for(auto& sock : m_socks)
        {
            sock->cancelAll();
            sock->close();
        }
        m_socks.clear(); });
}

void TcpServer::handleClient(Socket::ptr client)
{
    LOG(DEBUG, "handleclient:%p ", client.get());
}

std::string TcpServer::toString(const std::string &prefix)
{
    std::stringstream ss;
    ss << prefix << "[type=" << m_type
       << " name=" << m_name
       << " io_worker=" << (m_ioWorker ? m_ioWorker->getName() : "")
       << " accept=" << (m_acceptWorker ? m_acceptWorker->getName() : "")
       << " recv_timeout=" << m_recvTimeout << "]" << std::endl;
    std::string pfx = prefix.empty() ? "   " : prefix;
    for (auto &sock : m_socks)
    {
        ss << pfx << pfx << *sock << std::endl;
    }

    return ss.str();
}
